<!DOCTYPE html>
<html>

<head>
  <meta charset=utf-8 />
  <title>Event Timing: entries should be observable by its own frame.</title>
  <meta name="timeout" content="long">
</head>

<body>
<button id='button'>Generate a 'click' event</button>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/testdriver.js></script>
<script src=/resources/testdriver-actions.js></script>
<script src=/resources/testdriver-vendor.js></script>

<script src=resources/event-timing-test-utils.js></script>
<iframe id='iframe' src=resources/crossiframe-childframe.html></iframe>
<script>
  let clickTimeMin;
  let clickDone;

  function validateEntries(entries) {
    assert_equals(entries.length, 1, "Only 1 entry should be received");
    const entry = entries[0];
    verifyClickEvent(entry, 'button', true);

    assert_less_than(entry.processingStart, clickDone,
        "The entry's processing start should be before clickDone.");
    assert_greater_than(entry.startTime, clickTimeMin,
        "The entry's start time should be later than clickTimeMin.");
  }

  function validateChildFrameEntries(childFrameData) {
    if (childFrameData === "failed") {
      assert_unreached("Did not receive exactly one entry from child as expected");
    }
    // |childFrameData| has properties with the same names as its
    // PerformanceEventTiming counterpart.
    verifyClickEvent(childFrameData, null);
    assert_equals(childFrameData.target, 'iframe_div');

    assert_less_than(childFrameData.processingStart, childFrameData.clickDone,
        "The entry's processing start should be before than the child frame's clickDone.");
  }

  promise_test(async t => {
    assert_implements(window.PerformanceEventTiming, "Event Timing is not supported");
    // Wait for load event so we can interact with the iframe.
    await new Promise(resolve => {
      window.addEventListener('load', resolve);
    });
    clickTimeMin = performance.now();
    let observedMouseDown = false;
    const observerPromise = new Promise(resolve => {
      new PerformanceObserver(t.step_func(entries => {
        const mouseDowns = entries.getEntriesByName('mousedown');
        // Ignore the callback if there were no mousedown entries.
        if (mouseDowns.length === 0)
          return;

        assert_false(observedMouseDown,
            "Observer of main frames should only capture main-frame event-timing entries");
        validateEntries(mouseDowns);
        observedMouseDown = true;
        resolve();
      })).observe({type: 'event'});
    });
    clickAndBlockMain('button').then(() => {
      clickDone = performance.now();
    });
    const childFrameEntriesPromise = new Promise(resolve => {
      window.addEventListener("message", (event) => {
        // testdriver-complete is a webdriver internal event
        if (event.data.type != "testdriver-complete") {
          t.step(() => {
            validateChildFrameEntries(event.data);
          });
          resolve();
        }
      }, false);
    });
    // Tap on the iframe, with an offset of 10 to target the div inside it.
    const actions = new test_driver.Actions()
        .pointerMove(10, 10, { origin: document.getElementById("iframe") })
        .pointerDown()
        .pointerUp();
    actions.send();
    return Promise.all([observerPromise, childFrameEntriesPromise]);
  }, "Event Timing: entries should only be observable by its own frame.");

</script>
</body>
</html>
